#include <vfs.h>

#include <input-event-codes.h>
#include <wm.h>
#include <gato/surface.h>
#include <gato/render.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <malloc.h>
#include <types.h>
#include <spawn.h>

#define W 640
#define H 120
#define N 5

#define fclampf(v, a, b) fminf(fmaxf(a, v), b)

static void draw_icon(surface_t *base, float size, float x, float y)
{
    float scale = size / 60.0;

    draw_rectangle(base, x + 5 * scale, y + 5 * scale, size - 10 * scale, size - 10 * scale, 10, (style_t){
        fill_color : RGB(0xFF00BFA5),
        border_radius : {1, 1, 1, 1},
        stroke_color : ARGB(0x2FB2B2B2),
        stroke_width : 1,
    });
}

static float calc(int dis)
{
    return fclampf(fabsf(60 * 1.8 - 0.25 * fabsf(dis)), 60, 60 * 1.8);
}

static float f(float x, float b, float A)
{
    float f1 = x;
    float f2 = 0;
    float k = 130;

    if ((x > b - k) && (x < b + k))
    {
        f2 = A * sinf(3.1415926f * (x - b) / (2 * k)) + A;
    }
    else if (x >= b + k)
    {
        f2 = 2 * A;
    }

    return f1 + f2;
}

struct
{
    int w;
    int off;
    int size;
} list[N] = {0};

int dock_is_hit(int m_x, int m_y)
{
    for (int i = 0; i < N; i++)
    {
        float item_x = list[i].off;
        float item_size = list[i].size;

        if (m_x >= item_x && m_x <= item_x + item_size && (H - m_y) < item_size)
        {
            return i;
        }
    }
    return -1;
}

void dock(surface_t *base, int m_x, int m_y)
{
    surface_clear(base, ARGB(0), 0, 0, base->width, base->height);
    int fps = 30;
    static float center = 0.0f;
    static float A = 0;

    int total = 0;

    for (int i = 0; i < N; i++)
    {
        list[i].w = 60;
    }

    float left = W / 2 - 60 * N / 2.0;
    float right = W / 2 + 60 * N / 2.0;

    if (dock_is_hit(m_x, m_y) == -1)
    {
        A = fclampf(A - 8 * 40.0 / fps, 0, 60);
    }
    else
    {
        A = fclampf(A + 8 * 40.0 / fps, 0, 60);
    }

    center = f(m_x, m_x, A);

    for (int i = 0, x = W / 2 - 60 * N / 2.0; i < N; i++)
    {
        float d1 = m_x + f(x, m_x, A) - center;
        list[i].off = d1;
        x += list[i].w;
        float d2 = m_x + f(x, m_x, A) - center;
        list[i].size = d2 - d1;
    }

    draw_rectangle(base, list[0].off, H - 60 - 10, list[N - 1].size + list[N - 1].off - list[0].off, 60, 10, (style_t){
        fill_color : ARGB(0x2fD2D2D2),
        border_radius : {1, 1, 1, 1},
        stroke_color : ARGB(0x2FB2B2B2),
        stroke_width : 1,
    });

    for (int i = 0; i < N; i++)
    {
        draw_icon(base, list[i].size, list[i].off, H - list[i].size - 10);
    }
}

int main(int argc, char **argv)
{
    do_wm_init();
    window_t *win = wm_window_create(0, 480 - H, W, H, ARGB(0));
    wm_window_event_mask_set(win, WM_ABS_EVENT | WM_MOUSEBUTTONDOWN_EVENT | WM_MOUSE_OUT_EVENT);
    wm_window_show(win);
    surface_t *base = surface_alloc(W, H);

    dock(base, 0, 0);
    surface_cover(win->connect.surface, base, 0, 0);
    wm_window_update(win);

    int pos_x = 0, pos_y = 0;

    while (1)
    {
        wm_event_t e;
        kduration_t timeout = ms_to_kduration(16);

        int ret = wm_window_poll_event(win, &e, &timeout);
        // printf("WM_FLUSH_EVENT %d %d\n", pos_x, pos_y);

        if (ret == 0)
        {
            dock(base, pos_x, pos_y);
            surface_cover(win->connect.surface, base, 0, 0);
            wm_window_update(win);
        }
        else if (WM_ABS_EVENT == e.type)
        {
            pos_x = e.abs_event.x;
            pos_y = e.abs_event.y;

            dock(base, pos_x, pos_y);
            surface_cover(win->connect.surface, base, 0, 0);
            wm_window_update(win);
        }
        else if (WM_MOUSEBUTTONDOWN_EVENT == e.type)
        {
            int x = e.mouse_buttondown_event.x;
            int y = e.mouse_buttondown_event.y;
            int item = dock_is_hit(x, y);

            if (item == 0)
            {
                spawn(NULL, "/bin/eyes", NULL, 0, NULL, NULL);
            }
            else if (item == 1)
            {
                spawn(NULL, "/bin/game", NULL, 0, NULL, NULL);
            }
            else if (item == 2)
            {
                spawn(NULL, "/bin/test", NULL, 0, (char *[]){"/bin/eyes", "from_dock", NULL}, (char *[]){"abc", "123", NULL});
            }
        }
        else if (WM_MOUSE_OUT_EVENT == e.type)
        {
            pos_y = 0;
            dock(base, pos_x, pos_y);
            surface_cover(win->connect.surface, base, 0, 0);
            wm_window_update(win);
        }
    }
    return 0;
}